use windows::Devices::Usb;
use windows::Devices::Usb::{UsbBulkInPipe, UsbReadOptions};
use crate::define::{BulkInPipe, BulkOutPipe, UsbInterface, MResult};
use async_trait::async_trait;
use futures::channel::mpsc::{channel, Receiver};
use futures::executor::block_on;
use log::{debug, warn};
use windows::Storage::Streams::DataReader;
use crate::usb::UsbError::Unknown;


pub(crate) struct OsBulkInPipe{
    ctx: UsbBulkInPipe,
    reader: Option<DataReader>,
}

#[async_trait]
impl BulkInPipe for OsBulkInPipe{
    async fn read(&mut self, data : &mut [u8]) ->MResult<usize> {
        if self.reader.is_none() {
            let stream = self.ctx.InputStream()?;
            let r = DataReader::CreateDataReader(&stream)?;
            self.reader = Some(r);
        }
        let mut n = 0;
        if let Some(reader) = &self.reader{
            let size = data.len();
            n = reader.LoadAsync(size as _)?.await? as usize;
            let  (left, _) = data.split_at_mut(n);
            reader.ReadBytes(left)?;
        }
        Ok(n)
    }


}
impl From<Usb::UsbBulkInPipe> for OsBulkInPipe{
    fn from(value: Usb::UsbBulkInPipe) -> Self {

        Self{
            ctx: value,
            reader: None
        }
    }
}
pub(crate) struct OsBulkOutPipe{
    ctx: Usb::UsbBulkOutPipe
}

impl BulkOutPipe for OsBulkOutPipe{

}
impl From<Usb::UsbBulkOutPipe> for OsBulkOutPipe{
    fn from(value: Usb::UsbBulkOutPipe) -> Self {
        Self{
            ctx: value,
        }
    }
}

pub(crate) struct OsInterface{
    ctx: Usb::UsbInterface,
}
impl From<Usb::UsbInterface> for OsInterface{


    fn from(value: Usb::UsbInterface) -> Self {
        Self{
            ctx: value,
        }
    }
}

impl OsInterface {
    fn find_in_pip(&self, endpoint: usize)->MResult<UsbBulkInPipe>{
        let list = self.ctx.BulkInPipes()?;
        for p in list {
            let num = p.EndpointDescriptor()?.EndpointNumber()? as usize;
            if endpoint == num{
                return Ok(p);
            }
        }
        return Err(Unknown(format!("找不到Endpoint: {}", endpoint)));
    }
}
impl UsbInterface for OsInterface {
    fn number(&self) -> MResult<usize> {
        let num = self.ctx.InterfaceNumber()?;
        Ok(num as _)
    }

    fn get_bulk_in_pipes(&self) -> MResult<Vec<Box<dyn BulkInPipe>>> {
        let list = self.ctx.BulkInPipes()?;
        let out = list
            .into_iter()
            .map(|v|{
                let one = OsBulkInPipe::from(v);
                Box::new(one) as Box<dyn BulkInPipe>
            });

        Ok(out.collect())
    }

    fn get_bulk_out_pipes(&self) -> MResult<Vec<Box<dyn BulkOutPipe>>> {
        let list = self.ctx.BulkOutPipes()?;
        let out = list
            .into_iter()
            .map(|v|{
                let one = OsBulkOutPipe::from(v);
                Box::new(one) as Box<dyn BulkOutPipe>
            });

        Ok(out.collect())
    }

    fn open_bulk_in_channel(&self, package_len: usize, endpoint: usize) -> MResult<Receiver<Vec<u8>>> {
        let pip= self.find_in_pip(endpoint)?;
        let stream = pip.InputStream()?;
        let reader = DataReader::CreateDataReader(&stream)?;

        let (mut tx, rx)= channel(4);

        std::thread::spawn(move || block_on(async move{
            let package_size = package_len as _;
            loop {
                match reader.LoadAsync(package_size).unwrap().await{
                    Ok(n) => {
                        let mut buf = vec![0; n as _];
                        reader.ReadBytes(buf.as_mut_slice()).unwrap();
                        match tx.try_send(buf){
                            Ok(_) => {}
                            Err(e) => {
                                if e.is_full() {
                                    warn!("bulk channel full!");
                                }
                                if e.is_disconnected() {
                                    break;
                                }
                            }
                        };
                    }
                    Err(_) => {
                        break;
                    }
                }
            }
            if let Err(e) = reader.Close(){
                warn!("关闭Reader失败: {}", e);
            }
            debug!("发送停止");
        }));


        Ok(rx)
    }
}